/*
* Copyright 2010 Competentum group
*
* Licensed under the GNU General Public License, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.gnu.org/licenses/gpl.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.competentum.lib.parser
{
	import mx.core.mx_internal;
	use namespace mx_internal;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.FileReference;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.ByteArray;
	
	import mx.controls.Alert;
	import mx.managers.PopUpManager;
	import com.competentum.lib.events.InputOutputDataEvent;
	import mx.events.FlexEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileStream;
	import flash.filesystem.FileMode;

	/**
	 * Performs the full process with opening xml-file.
	 * Returns already decrypted data.
	 * Shows messages according to current phase.
	 * 
	 * @author Valentine Abanosimov
	 * */
	public class Opener extends EventDispatcher
	{
		private var defaultData:String;
		private var alert:Alert;
		private var fileReference:FileReference;
		private var file:File;
		private var enableBrowsingDialog:Boolean;
		private var typeFilter:Array;
		private var openedFileName:String;
		
		public function Opener(defaultData:String = null, enableBrowsingDialog:Boolean = false, typeFilter:Array = null)
		{
			super();
			if (defaultData)
			{
				this.defaultData = defaultData;
			}
			this.enableBrowsingDialog = enableBrowsingDialog;
			this.typeFilter = typeFilter;
		}
		
		/**
		 * If url specified, tries to open it. If not — shows browse dialog if it's enabled
		 * */
		public function open(url:String):void
		{
			showLoadingAlert();
			if (url != null && url != '')
			{
				loadConfigurationXML(url);
			}
			else
			{
				if (enableBrowsingDialog)
				{
					//try to open browser
					fileReference = new FileReference();
					fileReference.browse(typeFilter);
					fileReference.addEventListener(Event.SELECT, fileSelectedHandler);
					fileReference.addEventListener(Event.CANCEL, cancelHandler);
				}
				else
				{
					// try to decrypt defaultXML
					sendData(defaultData);
				}
			}
		}
		
		public function openAIR(url:String):void
		{
			showLoadingAlert();
			if (url != null && url != '')
			{
				file = new File(url);
				onAIROpening();
			}
			else
			{
				if (enableBrowsingDialog)
				{
					//try to open browser
					file = File.applicationStorageDirectory;
					file.addEventListener(Event.SELECT, onAIROpening);
					file.addEventListener(Event.CANCEL, cancelHandler);
					file.browseForOpen('Open xml', typeFilter);
				}
				else
				{
					// try to decrypt defaultXML
					sendData(defaultData);
				}
			}
		}
		
		private function fileSelectedHandler(event:Event):void
		{
			fileReference.load();
			fileReference.addEventListener(Event.COMPLETE, loadCompletedHandler);
		}
		
		
		private function onAIROpening(event:Event = null):void
		{
			var stream:FileStream = new FileStream();
			stream.open(file, FileMode.READ);
			var source:String = stream.readUTFBytes(stream.bytesAvailable);
			stream.close();
			openedFileName = file.nativePath;
			sendData(source);
		}
		
		private function cancelHandler(event:Event = null):void
		{
			removeLoadingAlert();
		}
		
		private function loadCompletedHandler(event:Event = null):void
		{
			openedFileName = fileReference.name;
			sendData(new XML(fileReference.data));
		}
		
		protected function showLoadingAlert():void
		{
			alert = Alert.show('\nOpening file');
			alert.mx_internal::alertForm.mx_internal::buttons[0].enabled = false;
			alert.mx_internal::alertForm.removeChild(alert.mx_internal::alertForm.mx_internal::buttons[0]);
			var animatedLoader:AnimatedLoader = new AnimatedLoader();
			animatedLoader.x = alert.width / 2 - 11;
			animatedLoader.y = 10;
			alert.mx_internal::alertForm.addChild(animatedLoader);
		}

		private function loadConfigurationXML(xmlUrl:String):void
		{
			// if we are provided with url, try to load xml and then parse it
			var request:URLRequest = new URLRequest();
			var loader:URLLoader = new URLLoader();
			loader.addEventListener(Event.COMPLETE, onLoadComplete);			
			loader.addEventListener(IOErrorEvent.IO_ERROR, onLoadFailed);
			
			request.url = xmlUrl;
			loader.load(request);
		}
		
		private function onLoadComplete(event:Event):void
		{
			var loader:URLLoader = event.target as URLLoader;
			if (loader != null)
			{
				sendData(String(loader.data));
			}
		}
		
		protected function onLoadFailed(event:IOErrorEvent):void
		{
			//Alert.show("XML Loading failed " + event.type+" "+event.text, "{XMLParser}");
			
			// try to decrypt defaultXML xml with default parametrs
			sendData(defaultData);
		}
		
		/**
		 * Tries to decrypt loadedXML and dispatch InputOutputDataEvent for stating parse xml.
		 * @see InputOutputManager
		 * @param loadedXML
		 */		
		private function sendData(loadedData:String):void
		{
			if (loadedData)
			{
				var event:InputOutputDataEvent = new InputOutputDataEvent(InputOutputDataEvent.CONFIGURATION_IS_LOADED);
				event.data = loadedData;
				event.filePath = openedFileName;
				removeLoadingAlert();
				dispatchEvent(event);
			}
		}
		
		/**
		 *  Closes loading alert
		 */		
		protected function removeLoadingAlert():void
		{
			if (alert && alert.isPopUp)
			{
				if(alert.initialized){
					PopUpManager.removePopUp(alert);
					alert = null;
				}else{
					alert.addEventListener(FlexEvent.CREATION_COMPLETE, onApplicationCreationComplete);
				}
			}
		}
		
		private function onApplicationCreationComplete(event:FlexEvent):void
		{
			alert.removeEventListener(FlexEvent.CREATION_COMPLETE, onApplicationCreationComplete);
			removeLoadingAlert();
		}
	}
}